/*
 * image2bin.cpp
 * 图像转二进制模块
 * 功能：
 * 1. 读取处理后的图像
 * 2. 提取图像数据
 * 3. 数据校验和纠错
 * 4. 转换为二进制格式
 * 输出：生成二进制数据文件
 */

#pragma once
#include"head.h"

const int sideSize;
const int whiteBlockWidth;
double rowWidth;
double colWidth;
bool error_row[42];
bool error_col[42];
double rowoffset;
double coloffset;
const int squareSize;
const int blockSize;
const int dataBegin;
const int dataSize;
const int offset;

int getfilenum(string folderpath);

int getcolor(Mat& image, int row, int column);

int getno(Mat& image);

int getsize(Mat& image);

void getdata(Mat& image, int data[]);

void getcode(Mat& image, int code[]);

bool check(int data[], int code[]);

void img2bin(string binpath);

void writetobin(string binpath);

unsigned char bit2byte();

void correct(short data[], short code[]);

const int sideSize = 50 * whiteBlockWidth;
const int whiteBlockWidth = 8;
double rowWidth;
double colWidth;
double rowoffset;
double coloffset;
bool error_row[42];
bool error_col[42];
const int squareSize = 7 * whiteBlockWidth;
const int blockSize = 3 * whiteBlockWidth;
const int dataBegin = 8 * whiteBlockWidth;
const int dataSize = (sideSize - dataBegin) / whiteBlockWidth;//42
queue <short> indata;


int getfilenum(string folderpath) {
    int filenum = 0;
    for (const auto& entry : fs::directory_iterator(folderpath))
        if (entry.is_regular_file())
            filenum++;
    return filenum;
}

int getcolor(Mat& image, int row, int column) {
    int whitenum = 0;
    cv::Vec3b color;
    for (int i = 0; i < rowWidth; i++)
        for (int j = 0; j < colWidth; j++) {
            color = image.at<cv::Vec3b>(row + i + rowoffset, column + j + coloffset);
            if (static_cast<int>(color[0]) + static_cast<int>(color[1]) + static_cast<int>(color[2]) > 382)
                whitenum++;
        }
    return (whitenum > rowWidth * colWidth / 2 ? 0 : 1);
}

int getno(Mat& image) {
    int a[16] = { 0 };
    int no = 0;
    for (int i = 0; i < 16; i++) {
        a[i] = getcolor(image, 0, (8 + i) * colWidth);
        no *= 2;
        no += a[i];
    }
    return no;
}

int getsize(Mat& image) {
    int a[16] = { 0 };
    int size = 0;
    for (int i = 0; i < 16; i++) {
        a[i] = getcolor(image, 0, (26 + i) * colWidth);
        size *= 2;
        size += a[i];
    }
    return size;
}

void getdata(Mat& image, short data[]) {
    if (!image.empty())
        for (int i = 0; i < dataSize; i++)
            for (int j = 0; j < dataSize; j++)
                data[i * dataSize + j] = getcolor(image, (8 + i) * rowWidth, (8 + j) * colWidth);
}

void getcode(Mat& image, short code[]) {
    if (!image.empty()) {
        for (int i = 0; i < 12; i++)
            for (int j = 0; j < 7; j++)
                code[i * 7 + j] = getcolor(image, (8 + i) * rowWidth, (0 + j) * colWidth);
    }
}

bool check(short data[], short code[]) {
    int res = 0;
    bool ret = true;
    for (int i = 0; i < dataSize; i++) {//У
        res = 0;
        for (int j = 0; j < dataSize; j++)
            res = res ^ data[i * dataSize + j];
        res = res ^ code[i];
        if (res) {
            error_row[i] = 1;
            ret = false;
        }
    }
    for (int i = 0; i < dataSize; i++) {//У
        res = 0;
        for (int j = 0; j < dataSize; j++)
            res = res ^ data[i + dataSize * j];
        res = res ^ code[dataSize + i];
        if (res) {
            error_col[i] = 1;
            ret = false;
        }
    }
    return ret;
}


unsigned char bit2byte() {
    unsigned char ret = 0;
    for (int i = 0; i < 8; i++) {
        ret *= 2;
        if (!indata.empty()) {
            ret += indata.front();
            indata.pop();
        }
    }
    return ret;
}
void writetobin(string binpath) {
    std::fstream file(binpath, ios::out | ios::binary);
    if (!file.is_open())
        std::cerr << "Failed to create file." << std::endl;
    int size = ceil(indata.size() / 8);
    for (int i = 0; i < size; i++) {
        unsigned char data = bit2byte();
        file.write(reinterpret_cast<const char*>(&data), 1);
    }
    file.close();
}
void img2bin(string binpath)
{
    string folderpath = "Dst_image";

    int filenum = getfilenum(folderpath);
    short data[2000], code[100];
    for (int i = 1; i <= filenum; i++) {
        /*string filepath = folderpath + "\\" + to_string(i) + ".png";*/
        string filepath = folderpath + "\\" + to_string(i) + ".png";
        Mat image = imread(filepath);
        cout << image.rows << " " << image.cols << endl;
        rowWidth = image.rows * 1.0 / 54;
        colWidth = image.cols * 1.0 / 54;
        rowoffset = 2 * rowWidth;
        coloffset = 2 * colWidth;
        getdata(image, data);
        getcode(image, code);
        /*if (!check(data, code))
            correct(data, code);*/
        if (!check(data, code))
            cout << "" << i << "ͼƬϢ" << endl;
        int size = getsize(image);
        for (int i = 0; i < size; i++)
            indata.push(data[i]);
    }
    writetobin(binpath);
    cout << "The bin file has generated successfully!" << endl;
}